package com.parse.tree.parsers.service.java;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

import com.commons.ParsingResult;
import com.parse.tree.parsers.java.JavaLexer;
import com.parse.tree.parsers.java.JavaParser;

public class CustomJavaParser implements Callable<ParsingResult> {

	private List<org.antlr.runtime.tree.Tree> variableDeclartorNodes = new ArrayList<org.antlr.runtime.tree.Tree>();
	private List<String> typeNodes = new ArrayList<String>();
	private List<String> variableList = new ArrayList<String>();
	private List<String> keywordList = new ArrayList<String>();
	private List<String> inStringList = new ArrayList<String>();
	private final String[] javaKeywords = { "abstract", "assert", "boolean",
			"break", "byte", "case", "catch", "char", "class", "const",
			"continue", "default", "do", "double", "else", "enum", "extends",
			"false", "final", "finally", "float", "for", "goto", "if",
			"implements", "import", "instanceof", "int", "interface", "long",
			"native", "new", "null", "package", "private", "protected",
			"public", "return", "short", "static", "strictfp", "super",
			"switch", "synchronized", "this", "throw", "throws", "transient",
			"true", "try", "void", "volatile", "while" };
	private final Set<String> javaKeywordSet = new HashSet<String>(
			Arrays.asList(javaKeywords));
	private final String fileName;
	private final CountDownLatch countDownLatch;
	private ParsingResult parsingResult;

	public CustomJavaParser(String fileName, CountDownLatch countDownLatch) {
		this.fileName = fileName;
		parsingResult = new JavaParsingResult();
		this.countDownLatch = countDownLatch;

	}

	@Override
	public ParsingResult call() {

		try {
			ANTLRFileStream input = new ANTLRFileStream(fileName);
			JavaLexer lexer = new JavaLexer(input);
			CommonTokenStream tokens = new CommonTokenStream(lexer);
			JavaParser parser = new JavaParser(tokens);
			JavaParser.javaSource_return r = parser.javaSource();
			CommonTree t = (CommonTree) r.getTree();
			parseTree(t, 1);

			for (Tree variableTree : variableDeclartorNodes) {
				Tree variable = variableTree.getChild(0);
				variableList.add(variable.toString());
				// printTree(variableTree, 1);
			}
			parsingResult.setKeywordList(keywordList);
			parsingResult.setTypeNodes(typeNodes);
			parsingResult.setVariableList(variableList);
			parsingResult.setStringNodes(inStringList);
			return parsingResult;
		} catch (Exception e) {
			System.out.println("Exception in parsing file" + e);
			return null;
		}finally{
			countDownLatch.countDown();
		}

	}

	public void parseTree(Tree t, int indent) {
		//System.out.println(t.toString());
		parseTreeHelper(t, indent);
	}

	private void parseTreeHelper(Tree t, int indent) {

		if (t != null) {
			StringBuffer sb = new StringBuffer(indent);
			for (int i = 0; i < indent; i++)
				sb = sb.append("   ");
			for (int i = 0; i < t.getChildCount(); i++) {
				int type = t.getChild(i).getType();
				if (type == JavaParser.VAR_DECLARATOR) {
					variableDeclartorNodes.add(t.getChild(i));
				}
				if (type == JavaParser.TYPE) {
					Tree typeNode = t.getChild(i);
					while (typeNode.getChildCount() > 0)
						typeNode = typeNode.getChild(0);
					// System.out.println("Type Child: "+ typeNode.toString());
					typeNodes.add(typeNode.toString());
				}
				if (type == JavaParser.STRING_LITERAL) {
					String s1 = t.getChild(i).toString();
					s1 = s1.substring(1, s1.length() - 1);
					if (s1 != null) {
						System.out.println(s1);
						String[] split = s1.split(" ");
						for (String s2 : split) {
							System.out.println(s2);
							inStringList.add(s2);
						}
					}
				}
				String nodeValue = t.getChild(i).toString();
				if (javaKeywordSet.contains(nodeValue))
					keywordList.add(nodeValue);

				// if (t.getChild(i).getType()==4)
				// System.out.println(sb.toString() + t.getChild(i).toString()
				// + " [" + JavaParser.tokenNames[type] + "]");
				parseTreeHelper((CommonTree) t.getChild(i), indent + 1);
			}
		}

	}

}
